home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue30 / diffm133 / DIFFM133.ZIP / SOURCE / aDiff.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-12-26  |  10.0 KB  |  425 lines

  1. {***********************************************}
  2. {                                               }
  3. {  Diff Maker                                   }
  4. {  Copyright (c) 1997 S.Kurinny & S.Kostinsky   }
  5. {                                               }
  6. {***********************************************}
  7.  
  8. unit aDiff;
  9.  
  10. interface
  11. Uses SysUtils, Classes, aCRC32;
  12.  
  13. {-------------------------------------------------}
  14.  
  15. Const
  16.   BufSize=2048*1024;
  17.  
  18. type
  19.   PInteger=^Integer;
  20.   TMyProcedure=procedure;
  21.   TByteArray=Array[1..MaxInt] of byte;
  22.   PByteArray=^TByteArray;
  23.  
  24.      TDiffCompData=record
  25.        InBuf      : PByteArray;      {pointer to input buffer}
  26.        UseBuf     : PByteArray;      {pointer to use buffer}
  27.        InBufSize  : integer;         {input buffer size}
  28.        UseBufSize : integer;         {use buffer size}
  29.        MaxLevel   : integer;         {max search level}
  30.        MaxLength  : integer;         {max string length}
  31.        MinLength  : integer;         {min string length}
  32.        OutBuf     : PByteArray;
  33.        OutSpBuf   : PByteArray;
  34.        OutBufSize : PInteger;
  35.        OutSpBufSize:PInteger;
  36.        EnoughLen   :integer;
  37.      end;
  38.  
  39. {-------------------------------------------------}
  40.  
  41. { Calculates hash value
  42.   3 bytes to 0..32767 }
  43. Function CalcHash(a,b,c:Integer):Integer;
  44.  
  45. { Compares buffers and returns number of equal bytes
  46.   Len - max length }
  47. function comp(var a,b;len:integer):integer;
  48. Function Min(a,b:integer):integer;
  49. Function Max(a,b:integer):integer;
  50. procedure DiffStreamCompress(InStream,UseStream,OutStream:TStream;Notify:TmyProcedure;MaxLev:Integer);
  51. procedure DiffCompress(D:TDiffCompData);
  52. procedure DiffStreamExtract(InStream,UseStream,OutStream:TStream;Notify:TMyProcedure);
  53.  
  54. {-------------------------------------------------}
  55.  
  56. Const
  57.   SSmallBuffer='Buffer size should be at least 4 bytes';
  58.  
  59. {-------------------------------------------------}
  60. implementation
  61. {-------------------------------------------------}
  62.  
  63. Const
  64.   MaxHashValue=131071;
  65.   cMaxFastData=6;
  66.  
  67. type
  68.   t3word=record
  69.     len:word;
  70.     useofs:integer;
  71.     bufofs:integer;
  72.   end;
  73.   p3word=^t3word;
  74.  
  75.   arrayt3word=array[0..Maxint div 20] of t3word;
  76.   parrayt3word=^arrayt3word;
  77.  
  78.   THashTable=Array[0..MaxHashValue] of Integer;
  79.   PHashTable=^THashTable;
  80.   THashList=Array[1..MaxInt div 4] of integer;
  81.   PHashList=^THashList;
  82.  
  83. {-----------------------------------------}
  84.  
  85. Function Max(a,b:integer):integer;
  86. begin
  87.   If a>b then result:=a else result:=b;
  88. end;
  89.  
  90. {-----------------------------------------}
  91.  
  92. Function Min(a,b:integer):integer;
  93. begin
  94.   If a<b then result:=a else result:=b;
  95. end;
  96.  
  97. {----------------------------------------------------------------}
  98.  
  99. function comp(var a,b;len:integer):integer; assembler;
  100. asm
  101.     PUSH ESI
  102.     PUSH EDI
  103.     mov esi,a
  104.     mov edi,b
  105.     cld
  106.     mov eax,len
  107.     mov ecx,eax
  108.     rep cmpsb
  109.     inc ecx
  110.     sub eax,ecx
  111.     POP EDI
  112.     POP ESI
  113. end;
  114.  
  115. {--------------------------------------------------------}
  116.  
  117. procedure DiffCompress(D:TDiffCompData);
  118. Var
  119.   HTab:PHashTable;
  120.   HList:PHashList;
  121.   i:integer;
  122.   a,b,c:integer;
  123.   h:integer;
  124.   curofs:integer;
  125.   curlen:integer;
  126.   curlevel:integer;
  127.   templen:integer;
  128.   tempOFs:Integer;
  129.   oldh:integer;
  130.   x:integer;
  131.   t3:t3word;
  132.   curpos,cursppos:integer;
  133.  
  134. Label
  135.   l3,l2,l1;
  136. begin
  137.   With D do
  138.   begin
  139.  
  140.   If (InBufSize<4) or (UseBufSize<4) then
  141.     raise Exception.Create(SSmallBuffer);
  142.   CurPos:=1;
  143.   CurSpPos:=1;
  144.   New(HTab);
  145.   GetMem(HList,UseBufSize*4);
  146.   try
  147.     FillChar(HTab^,Sizeof(THashTable),0);
  148.     a:=UseBuf[1];
  149.     b:=UseBuf[2];
  150.     c:=UseBuf[3];
  151.     oldh:=maxint;
  152.     For i:=1 to UseBufSize-4 do
  153.     begin
  154.       h:=(a shl 9) xor (b shl 5) xor c;
  155.        If h<>oldh then
  156.        begin
  157.         HList^[i]:=HTab^[h];
  158.         HTab^[h]:=i;
  159.         oldh:=h;
  160.        end;
  161.       a:=b;b:=c;c:=UseBuf[i+3];
  162.     end;
  163.     {-------}
  164.     i:=1;
  165.     While i<=InBufSize do
  166.     begin
  167.       a:=InBuf[i];
  168.       if i>inbufsize-3 then goto l1;
  169.       h:=(a shl 9) xor (InBuf[i+1] shl 5) xor InBuf[i+2];
  170.       curlen:=minlength-1;
  171.       TempOFs:=HTab^[h];
  172.       curlevel:=0;
  173.       While (tempofs<>0) and (CurLevel<MaxLevel) do
  174.       begin
  175.         x:=Min(InBufSize-i,UseBufSize-TempOFs);
  176.         templen:=Comp(InBuf[i],UseBuf[TempOfs],x) and $0000ffff;
  177.         If TempLen>CurLen then
  178.         begin
  179.           CurLen:=TempLen;
  180.           CurOfs:=TempOfs;
  181.         end;
  182.      l3:
  183.         TempOfs:=HList^[TempOfs];
  184.         inc(CurLevel);
  185.       end;
  186.       If CurLen<MinLength then
  187.       begin
  188.       l1:
  189.         OutBuf[CurPos]:=a;
  190.         inc(CurPos);
  191.         Inc(i);
  192.       end else
  193.       begin
  194.     l2:
  195.        t3.len:=CurLen;
  196.        t3.useofs:=CurOfs;
  197.        t3.bufofs:=i;
  198.        Move(t3,OutSpBuf[CurSpPos],SizeOf(t3));
  199.        inc(CurSpPos,SizeOf(t3));
  200.        Inc(i,CurLen);
  201.       end;
  202.     end;
  203.     {-------}
  204.     t3.len:=0;
  205.     t3.useofs:=0;
  206.     t3.bufofs:=InBufSize+1;
  207.     Move(t3,OutSpBuf[CurSpPos],SizeOf(t3));
  208.     inc(CurSpPos,SizeOf(t3));
  209.     OutBufSize^:=CurPos-1;
  210.     OutSpBufSize^:=CurSpPos-1;
  211.   finally
  212.     Dispose(HTab);
  213.     FreeMem(HList,UseBufSize*4);
  214.   end;
  215.   end;
  216. end;
  217.  
  218. {-------------------------------------------------}
  219.  
  220. procedure DiffStreamCompress(InStream,UseStream,OutStream:TStream;Notify:TMyProcedure;MaxLev:Integer);
  221. Var
  222.    Buf,Temp,OutBuf,OutSpBuf:PByteArray;
  223.    BufRead,TempRead:Integer;
  224. {----}
  225.  
  226. procedure WriteByte(A:Byte);
  227. begin
  228.   OutStream.Write(A,1);
  229. end;
  230.  
  231. {----}
  232.  
  233. procedure WriteInt(A:Integer);
  234. begin
  235.   OutStream.Write(A,SizeOF(Integer));
  236. end;
  237.  
  238. {----}
  239.  
  240. procedure CompressBuf(Var aInBuf,aUseBuf;BufSize,UseSize,MaxLev:Integer);
  241. Var
  242.   dat:TDiffCompData;
  243.   obufsize,ospbufsize:integer;
  244. begin
  245.     Dat.OutBuf     :=OutBuf;
  246.     Dat.OutSpBuf   :=OutSpBuf;
  247.     With dat do
  248.     begin
  249.        InBuf      :=@TByteArray(aInBuf);
  250.        UseBuf     :=@TByteArray(aUseBuf);
  251.        InBufSize  :=BufSize;
  252.        UseBufSize :=UseSize;
  253.        MaxLevel   :=MaxLev;
  254.        MaxLength  :=65535;
  255.        MinLength  :=20;
  256.        OutBufSize :=@obufsize;
  257.        OutSpBufSize:=@ospbufsize;
  258.        EnoughLen:=1024;
  259.     end;
  260.     obufsize:=0;
  261.     ospbufsize:=0;
  262.     DiffCompress(Dat);
  263.  
  264.     WriteInt(OBufSize);
  265.     WriteInt(OSpBufSize);
  266.     OutStream.Write(OutBuf^,OBufSize);
  267.  
  268.     OutStream.Write(OutSpBuf^,OSpBufSize);
  269. end;
  270.  
  271. label l1;
  272.  
  273. {----}
  274.  
  275. begin
  276.   GetMem(Buf,BufSize);
  277.   GetMem(Temp,BufSize);
  278.   GetMem(OutBuf,BufSize);
  279.   GetMem(OutSpBuf,BufSize);
  280.   try
  281.     BufRead:=1;
  282.     While BufRead<>0 do
  283.     begin
  284.       BufRead:=InStream.Read(Buf^,BufSize);
  285.       TempRead:=UseStream.Read(Temp^,BufSize);
  286.       {--}
  287.       WriteInt(TempRead);
  288.       If (BufRead<4) or (TempRead<4) or (BufRead div 4>TempRead) then
  289.       begin
  290.         WriteByte(0); {block copied flag}
  291.         WriteInt(BufRead);
  292.         if bufread=0 then goto l1;
  293.         WriteInt(CalculateCRC32(Buf^,Bufread));
  294.         OutStream.Write(Buf^,BufRead);
  295.       end else
  296.       begin
  297.         WriteByte(1);{block compressed flag}
  298.         WriteInt(CalculateCRC32(Buf^,Bufread));
  299.         WriteInt(CalculateCRC32(Temp^,Tempread));
  300.         CompressBuf(Buf^,Temp^,BufRead,TempRead,MaxLev);
  301.       end;
  302.       l1:
  303.       If Assigned(Notify) then Notify;
  304.     end;
  305.   finally
  306.     FreeMem(OutBuf,BufSize);
  307.     FreeMem(OutSpBuf,BufSize);
  308.     FreeMem(Buf,BufSize);
  309.     FreeMem(Temp,BufSize);
  310.   end;
  311. end;
  312.  
  313. {-------------------------------------------------}
  314.  
  315. procedure DiffStreamExtract(InStream,UseStream,OutStream:TStream;Notify:TMyProcedure);
  316. Var
  317.    Buf,Temp,OutBuf,OutSpBuf:PByteArray;
  318.    curoutpos,BufRead,TempRead:Integer;
  319.  
  320. {----}
  321.  
  322. Function ReadByte:Byte;
  323. begin
  324.   InStream.Read(Result,1);
  325. end;
  326.  
  327. {----}
  328.  
  329. Function ReadInt:Integer;
  330. begin
  331.   InStream.Read(Result,SizeOF(Integer));
  332. end;
  333.  
  334. {----}
  335.  
  336. procedure ExtractBuf;
  337. Var
  338.   obufsize,ospbufsize:integer;
  339.   p:parrayt3word;
  340.   d,er,len,useofs,bufofs,i,psize:integer;
  341. begin
  342.     OBufSize:=ReadInt;
  343.     OSpBufSize:=ReadInt;
  344.  
  345.     InStream.Read(Buf^,OBufSize);
  346.     InStream.Read(OutSpBuf^,OSpBufSize);
  347.     p:=pointer(OutSpBuf);
  348.     psize:=OSpBufSize div sizeof(t3word);
  349.     er:=1;
  350.     curoutpos:=1;
  351.     For i:=0 to PSize-1 do
  352.     begin
  353.       len:=p^[i].len;
  354.       useofs:=p^[i].useofs;
  355.       bufofs:=p^[i].bufofs;
  356.  
  357.       d:=BufOfs-CurOutPos;
  358.       If d<>0 then
  359.       begin
  360.         Move(Buf[er],OutBuf[CurOutPos],d);
  361.         inc(er,d);
  362.         inc(CurOutPos,d);
  363.       end;
  364.       Move(Temp[UseOFs],OutBuf[CurOutPos],Len);
  365.       inc(CurOutPos,len);
  366.     end;
  367. end;
  368. {----}
  369.  
  370. Var CRC,BufCRC:Integer;
  371. label l1;
  372. begin
  373.   try
  374.     GetMem(Buf,BufSize);
  375.     GetMem(Temp,BufSize);
  376.     GetMem(OutBuf,BufSize);
  377.     GetMem(OutSpBuf,BufSize);
  378.     BufRead:=1;
  379.     While BufRead<>0 do
  380.     begin
  381.        TempRead:=ReadInt;
  382.        UseStream.Read(Temp^,Tempread);
  383.        Case ReadByte of
  384.          0: begin //copy
  385.               BufRead:=ReadInt;
  386.               If bufread=0 then goto l1;
  387.               CRC:=ReadInt;
  388.               InStream.Read(Buf^,Bufread);
  389.               If CRC<>CalculateCRC32(Buf^,Bufread) then
  390.                 raise Exception.Create('CRC Error');
  391.               OutStream.Write(Buf^,BufRead);
  392.             end;
  393.          1: begin //extract
  394.               BufCRC:=ReadInt;
  395.               CRC:=ReadInt;{tempcrc}
  396.               if CRC<>CalculateCRC32(Temp^,Tempread) then
  397.                 raise Exception.Create('CRC Error');
  398.               ExtractBuf;
  399.               If BufCRC<>CalculateCRC32(OutBuf^,CurOutPos-1) then
  400.                 raise Exception.Create('CRC Error');
  401.               OutStream.Write(OutBuf^,CurOutPos-1);
  402.             end;
  403.          else raise Exception.Create('CRC Error');
  404.        end;
  405.     l1:
  406.     If Assigned(Notify) then Notify;
  407.     end;
  408.   finally
  409.     FreeMem(OutBuf,BufSize);
  410.     FreeMem(OutSpBuf,BufSize);
  411.     FreeMem(Buf,BufSize);
  412.     FreeMem(Temp,BufSize);
  413.   end;
  414. end;
  415.  
  416. {-------------------------------------------------}
  417.  
  418. Function CalcHash(a,b,c:Integer):Integer;
  419. begin
  420.   Result:=(a shl 7) xor (b shl 4) xor c;
  421. end;
  422.  
  423. {-------------------------------------------------}
  424. end.
  425.